package cn.bertsir.zbar.view;


import cn.bertsir.zbar.ResourceTable;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.colors.RgbColor;
import ohos.agp.colors.RgbPalette;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.Point;
import ohos.agp.utils.Rect;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.global.resource.WrongTypeException;

import java.io.IOException;
import java.util.Base64;

/**
 * Created by Bert on 2019-09-16.
 * Mail: bertsir@163.com
 */
public class ScanLineView extends ComponentContainer implements Component.DrawTask {

    private static final String TAG = "ScanView";

    public static final int style_gridding = 0;//扫描区域的样式
    public static final int style_radar = 1;
    public static final int style_hybrid = 2;
    public static final int style_line = 3;


    private Rect mFrame;//最佳扫描区域的Rect

    private Paint mScanPaint_Gridding;//网格样式画笔
    private Paint mScanPaint_Radio;//雷达样式画笔
    private Paint mScanPaint_Line;//线条样式画笔

    private Path mBoundaryLinePath;//边框path
    private Path mGriddingPath;//网格样式的path

    private LinearShader mLinearGradient_Radar;//雷达样式的画笔shader
    private LinearShader mLinearGradient_Gridding;//网格画笔的shader
    private LinearShader mLinearGradient_line;
    private float mGriddingLineWidth = 2;//网格线的线宽，单位pix
    private int mGriddingDensity = 40;//网格样式的，网格密度，值越大越密集


    private float mCornerLineLen = 50f;//根据比例计算的边框长度，从四角定点向临近的定点画出的长度

    private Matrix mScanMatrix;//变换矩阵，用来实现动画效果
    private AnimatorValue mValueAnimator;//值动画，用来变换矩阵操作

    private int mScanAnimatorDuration = 1800;//值动画的时长
    private int mScancolor;//扫描颜色

    private int mScanStyle = style_gridding;//网格 0：网格，1：纵向雷达 2:综合 3:线
    private float animatedValue;


    public ScanLineView(Context context) {
        this(context, null);
    }

    // This constructor is used when the class is built from an XML resource.
    public ScanLineView(Context context, AttrSet attrs) {
        this(context, attrs, "0");
    }

    public ScanLineView(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @Override
    public void invalidate() {
        super.invalidate();
        addDrawTask(this::onDraw);
    }

    private void init() {
        // Initialize these once for performance rather than calling them every time in onDraw().
        mScanPaint_Gridding = new Paint();
        mScanPaint_Gridding.setStyle(Paint.Style.STROKE_STYLE);
        mScanPaint_Gridding.setStrokeWidth(mGriddingLineWidth);

        mScanPaint_Radio = new Paint();
        mScanPaint_Radio.setStyle(Paint.Style.FILL_STYLE);
        try {
            mScancolor = getResourceManager().getElement(ResourceTable.Color_common_color).getColor();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NotExistException e) {
            e.printStackTrace();
        } catch (WrongTypeException e) {
            e.printStackTrace();
        }


        mScanPaint_Line = new Paint();//创建一个画笔
        mScanPaint_Line.setStyle(Paint.Style.FILL_STYLE);//设置非填充
        mScanPaint_Line.setStrokeWidth(10);//笔宽5像素
        mScanPaint_Line.setAntiAlias(true);//锯齿不显示

        //变换矩阵，用来处理扫描的上下扫描效果
        mScanMatrix = new Matrix();
        mScanMatrix.setTranslate(0, 30);

        setArrangeListener(new ArrangeListener() {
            @Override
            public boolean onArrange(int i, int i1, int i2, int i3) {
//                System.out.println("========onArrange =="+i+"__"+i1+"__"+i2+"__"+i3);
                mFrame = new Rect(i, i1,i2, i3);
                initBoundaryAndAnimator();

                return true;
            }
        });

    }


    private void initBoundaryAndAnimator() {
        if (mBoundaryLinePath == null) {
            mBoundaryLinePath = new Path();
            mBoundaryLinePath.moveTo(mFrame.left, mFrame.top + mCornerLineLen);
            mBoundaryLinePath.lineTo(mFrame.left, mFrame.top);
            mBoundaryLinePath.lineTo(mFrame.left + mCornerLineLen, mFrame.top);
            mBoundaryLinePath.moveTo(mFrame.right - mCornerLineLen, mFrame.top);
            mBoundaryLinePath.lineTo(mFrame.right, mFrame.top);
            mBoundaryLinePath.lineTo(mFrame.right, mFrame.top + mCornerLineLen);
            mBoundaryLinePath.moveTo(mFrame.right, mFrame.bottom - mCornerLineLen);
            mBoundaryLinePath.lineTo(mFrame.right, mFrame.bottom);
            mBoundaryLinePath.lineTo(mFrame.right - mCornerLineLen, mFrame.bottom);
            mBoundaryLinePath.moveTo(mFrame.left + mCornerLineLen, mFrame.bottom);
            mBoundaryLinePath.lineTo(mFrame.left, mFrame.bottom);
            mBoundaryLinePath.lineTo(mFrame.left, mFrame.bottom - mCornerLineLen);
        }
        if (mValueAnimator == null) {
            initScanValueAnim(mFrame.bottom - mFrame.top);
        }
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {

        if (mFrame == null || mBoundaryLinePath == null) {
            return;
        }
//        initGriddingPathAndStyle();
//        canvas.drawPath(mGriddingPath, mScanPaint_Gridding);
        switch (mScanStyle) {

            case style_gridding:
                initGriddingPathAndStyle();
                canvas.drawPath(mGriddingPath, mScanPaint_Gridding);
                break;
            case style_radar:
                initRadarStyle();
                canvas.drawRect(mFrame, mScanPaint_Radio);
                break;
            case style_line:
                initLineStyle();
                canvas.drawLine(new Point(0, (mFrame.bottom - mFrame.top - Math.abs(animatedValue))), new Point(getEstimatedWidth(),
                        (mFrame.bottom - mFrame.top - Math.abs(animatedValue))), mScanPaint_Line);
                break;
            case style_hybrid:
            default:
                initGriddingPathAndStyle();
                initRadarStyle();
                canvas.drawPath(mGriddingPath, mScanPaint_Gridding);
                canvas.drawRect(mFrame, mScanPaint_Radio);
                break;

        }
    }

    private void initRadarStyle() {
        if (mLinearGradient_Radar == null) {
            mLinearGradient_Radar =new LinearShader(new Point[]{new Point(0, mFrame.top),new Point(0, mFrame.bottom + (0.01f * mFrame.getHeight()))},new float[]{0, 0.85f, 0.99f, 1f},
                    new Color[]{Color.TRANSPARENT, Color.TRANSPARENT, new Color(mScancolor), Color.TRANSPARENT}, Shader.TileMode.CLAMP_TILEMODE);
            mLinearGradient_Radar.setShaderMatrix(mScanMatrix);
            mScanPaint_Radio.setShader(mLinearGradient_Radar,Paint.ShaderType.LINEAR_SHADER);
        }
    }

    private void initLineStyle() {
        if (mLinearGradient_line == null) {
            String line_colors = String.valueOf(Integer.toHexString(mScancolor));
            line_colors = line_colors.substring(line_colors.length() - 6, line_colors.length() - 0);
            mLinearGradient_line =new LinearShader(new Point[]{new Point(0,0),new Point(getEstimatedWidth(),0)},null,
                    new Color[]{new Color(RgbPalette.parse("#00"+line_colors)),
                            new Color(mScancolor), new Color(RgbPalette.parse("#00"+line_colors))}, Shader.TileMode.CLAMP_TILEMODE);
            mLinearGradient_line.setShaderMatrix(mScanMatrix);
            mScanPaint_Line.setShader(mLinearGradient_line,Paint.ShaderType.LINEAR_SHADER);
        }
    }

    private void initGriddingPathAndStyle() {
        if (mGriddingPath == null) {
            mGriddingPath = new Path();
            float wUnit = mFrame.getWidth() / (mGriddingDensity + 0f);
            float hUnit = mFrame.getHeight() / (mGriddingDensity + 0f);
            for (int i = 0; i <= mGriddingDensity; i++) {
                mGriddingPath.moveTo(mFrame.left + i * wUnit, mFrame.top);
                mGriddingPath.lineTo(mFrame.left + i * wUnit, mFrame.bottom);
            }
            for (int i = 0; i <= mGriddingDensity; i++) {
                mGriddingPath.moveTo(mFrame.left, mFrame.top + i * hUnit);
                mGriddingPath.lineTo(mFrame.right, mFrame.top + i * hUnit);
            }
        }
        if (mLinearGradient_Gridding == null) {
            mLinearGradient_Gridding =new LinearShader(new Point[]{new Point(0, mFrame.top),new Point(0, mFrame.bottom + 0.01f * mFrame.getHeight())},new float[]{0, 0.5f, 0.99f, 1f},
                    new Color[]{Color.TRANSPARENT,Color.TRANSPARENT, new Color(mScancolor), Color.TRANSPARENT}, Shader.TileMode.CLAMP_TILEMODE);
            mLinearGradient_Gridding.setShaderMatrix(mScanMatrix);
            mScanPaint_Gridding.setShader(mLinearGradient_Gridding,Paint.ShaderType.LINEAR_SHADER);

        }
    }

    public void initScanValueAnim(int height) {

        mValueAnimator = new AnimatorValue();
        mValueAnimator.setDuration(mScanAnimatorDuration);
        mValueAnimator.setLoopedCount(AnimatorValue.INFINITE);
        mValueAnimator.setCurveType(Animator.CurveType.DECELERATE);
        mValueAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {

                if(mLinearGradient_Gridding == null){
                    initGriddingPathAndStyle();
                }
                if(mLinearGradient_Radar == null){
                    initRadarStyle();
                }
                if(mLinearGradient_line == null){
                    initLineStyle();
                }
                if (mScanMatrix != null ) {
                    animatedValue=v*1000;
//                    System.out.println("===Value===="+animatedValue);
                    mScanMatrix.setTranslate(0, animatedValue);
                    mLinearGradient_Gridding.setShaderMatrix(mScanMatrix);
                    mLinearGradient_Radar.setShaderMatrix(mScanMatrix);
                    mLinearGradient_line.setShaderMatrix(mScanMatrix);
//                    mScanPaint.setShader(mLinearGradient); //不是必须的设置到shader即可
                    invalidate();
                }
            }
        });
        mValueAnimator.start();
    }

//    @Override
//    protected void onDetachedFromWindow() {
//        if (mValueAnimator != null && mValueAnimator.isRunning()) {
//            mValueAnimator.cancel();
//        }
//        super.onDetachedFromWindow();
//    }

    //设定扫描的颜色
    public void setScancolor(int colorValue) {
        this.mScancolor = colorValue;
    }

    public void setScanAnimatorDuration(int duration) {
        this.mScanAnimatorDuration = duration;
    }


    /*
     * @description 扫描区域的样式
     * @scanStyle
     *
     * */
    public void setScanStyle(int scanStyle) {
        this.mScanStyle = scanStyle;
    }

    /*
     * 扫描区域网格的样式
     *  @params strokeWidth：网格的线宽
     * @params density：网格的密度
     * */
    public void setScanGriddingStyle(float strokeWidh, int density) {
        this.mGriddingLineWidth = strokeWidh;
        this.mGriddingDensity = density;
    }


}

